/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include "MDHCPInfoDesc.h"

#include <Winsock2.h>

//---------------------------------------------------------------------------

MDHCPInfoDesc::MDHCPInfoDesc(void)
{
}

MDHCPInfoDesc::~MDHCPInfoDesc(void)
{
}

//---------------------------------------------------------------------------

void MDHCPInfoDesc::BuildHexVal(char* buff, BYTE val)
{
	BYTE bbb;

	if(buff==NULL) return;

	bbb = val>>4;
	bbb &= 0x0F;
	if(bbb<10) buff[0] = '0' + (char)bbb;
	else       buff[0] = 'A' + (char)(bbb - 10);

	bbb = val & 0x0F;
	if(bbb<10) buff[1] = '0' + (char)bbb;
	else       buff[1] = 'A' + (char)(bbb - 10);
}

//---------------------------------------------------------------------------

CString MDHCPInfoDesc::GetOptionName(BYTE optIdIn)
{
	CString str;

	switch(optIdIn){
		/* RFC 2132 */
		case 1 :	str = _T("Subnet Mask");break;
		case 2 :	str = _T("Time Offset");break;
		case 3 :	str = _T("Router");break;
		case 4 :	str = _T("Time Server");break;
		case 5 :	str = _T("Name Server");break;
		case 6 :	str = _T("Domain Name Server");break;
		case 7 :	str = _T("Log Server");break;
		case 8 :	str = _T("Cookie Server");break;
		case 9 :	str = _T("LPR Server");break;
		case 10 :	str = _T("Impress Server");break;
		case 11 :	str = _T("Resource Location Server");break;
		case 12 :	str = _T("Host Name");break;
		case 13 :	str = _T("Boot File Size");break;
		case 14 :	str = _T("Merit Dump File");break;
		case 15 :	str = _T("Domain Name");break;
		case 16 :	str = _T("Swap Server");break;
		case 17 :	str = _T("Root Path");break;
		case 18 :	str = _T("Extensions Path");break;
		case 19 :	str = _T("IP Forwarding Enable/Disable");break;
		case 20 :	str = _T("Non-Local Source Routing Enable/Disable");break;
		case 21 :	str = _T("Policy Filter");break;
		case 22 :	str = _T("Maximum Datagram Reassembly Size");break;
		case 23 :	str = _T("Default IP Time-to-live");break;
		case 24 :	str = _T("Path MTU Aging Timeout");break;
		case 25 :	str = _T("Path MTU Plateau Table");break;
		case 26 :	str = _T("Interface MTU");break;
		case 27 :	str = _T("All Subnets are Local");break;
		case 28 :	str = _T("Broadcast Address");break;
		case 29 :	str = _T("Perform Mask Discovery");break;
		case 30 :	str = _T("Mask Supplier");break;
		case 31 :	str = _T("Perform Router Discovery");break;
		case 32 :	str = _T("Router Solicitation Address");break;
		case 33 :	str = _T("Static Route");break;
		case 34 :	str = _T("Trailer Encapsulation");break;
		case 35 :	str = _T("ARP Cache Timeout");break;
		case 36 :	str = _T("Ethernet Encapsulation");break;
		case 37 :	str = _T("TCP Default TTL");break;
		case 38 :	str = _T("TCP Keepalive Interval");break;
		case 39 :	str = _T("TCP Keepalive Garbage");break;
		case 40 :	str = _T("Network Information Service Domain");break;
		case 41 :	str = _T("Network Information Servers");break;
		case 42 :	str = _T("Network Time Protocol Servers");break;
		case 43 :	str = _T("Vendor Specific Information");break;
		case 44 :	str = _T("NetBIOS over TCP/IP Name Server");break;
		case 45 :	str = _T("NetBIOS over TCP/IP Datagram Distribution Server");break;
		case 46 :	str = _T("NetBIOS over TCP/IP Node Type");break;
		case 47 :	str = _T("NetBIOS over TCP/IP Scope");break;
		case 48 :	str = _T("X Window System Font Server");break;
		case 49 :	str = _T("X Window System Display Manager");break;
		case 50 :	str = _T("Requested IP Address");break;
		case 51 :	str = _T("IP Address Lease Time");break;
		case 52 :	str = _T("Option Overload");break;
		case 53 :	str = _T("DHCP Message Type");break;
		case 54 :	str = _T("Server Identifier");break;
		case 55 :	str = _T("Parameter Request List");break;
		case 56 :	str = _T("Message");break;
		case 57 :	str = _T("Maximum DHCP Message Size");break;
		case 58 :	str = _T("Renewal (T1) Time Value");break;
		case 59 :	str = _T("Rebinding (T2) Time Value");break;
		case 60 :	str = _T("Vendor class identifier");break;
		case 61 :	str = _T("Client-identifier");break;
		case 64 :	str = _T("Network Information Service+ Domain");break;
		case 65 :	str = _T("Network Information Service+ Servers");break;
		case 66 :	str = _T("TFTP server name");break;
		case 67 :	str = _T("Bootfile name");break;
		case 68 :	str = _T("Mobile IP Home Agent");break;
		case 69 :	str = _T("Simple Mail Transport Protocol (SMTP) Server");break;
		case 70 :	str = _T("Post Office Protocol (POP3) Server");break;
		case 71 :	str = _T("Network News Transport Protocol (NNTP) Server");break;
		case 72 :	str = _T("Default World Wide Web (WWW) Server");break;
		case 73 :	str = _T("Default Finger Server");break;
		case 74 :	str = _T("Default Internet Relay Chat (IRC) Server");break;
		case 75 :	str = _T("StreetTalk Server");break;
		case 76 :	str = _T("StreetTalk Directory Assistance (STDA) Server");break;

		/* RFC 2242 */
		case 62 :	str = _T("Netware/IP Domain Name");break;
		case 63 :	str = _T("Netware/IP sub Options");break;

		/* RFC 3004 */
		case 77 :	str = _T("User Class Information");break;

		/* RFC 2610 */
		case 78 :	str = _T("Directory Agent Information");break;
		case 79 :	str = _T("Service Location Agent Scope");break;

		/* RFC 4039 */
		case 80 :	str = _T("Rapid Commit");break;

		/* DRAFT-IETF-DHC-FQDN-OPTION */
		case 81 :	str = _T("Fully Qualified Domain Name");break;

		/* RFC 3046 */
		case 82 :	str = _T("Relay Agent Information");break;

		/* RFC 4174 */
		case 83 :	str = _T("Internet Storage Name Service");break;

		/* RFC2241 */
		case 85 :	str = _T("Novell Directory Services");break;
		case 86 :	str = _T("Novell Directory Services");break;
		case 87 :	str = _T("Novell Directory Services");break;

		/* RFC-ietf-dhc-bcmc-options-05 */
		case 88 :	str = _T("BCMCS Controller Domain Name list");break;
		case 89 :	str = _T("BCMCS Controller IPv4 address");break;

		/* RFC 3118 */
		case 90 :	str = _T("Authentication");break;

		/* RFC 4388 */
		case 91 :	str = _T("Client Last Transaction Time");break;
		case 92 :	str = _T("Associated IP");break;

		/* RFC 3679 */
		case 93 :	str = _T("Client System Architecture");break;
		case 94 :	str = _T("Client Network Device Interface");break;
		case 95 :	str = _T("Lightweight Directory Access Protocol");break;
		case 97 :	str = _T("UUID/GUID-based Client Identifier");break;

		/* RFC 2485 */
		case 98 :	str = _T("Open Group's User Authentication");break;

		/* RFC 3679 */
		case 112 :	str = _T("NetInfo Parent Server Address");break;
		case 113 :	str = _T("NetInfo Parent Server Tag");break;
		case 114 :	str = _T("URL");break;

		/* RFC 2563 */
		case 116 :	str = _T("DHCP Auto-Configuration");break;

		/* RFC 2937 */
		case 117 :	str = _T("Name Service Search");break;

		/* RFC 3011 */
		case 118 :	str = _T("Subnet Selection");break;

		/* RFC 3397 */
		case 119 :	str = _T("DNS Domain Serach List");break;

		/* RFC 3361 */
		case 120 :	str = _T("SIP Servers DHCP");break;

		/* RFC 3442 */
		case 121 :	str = _T("Classless Static Route");break;

		/* RFC 3495 */
		case 122 :	str = _T("CableLabs Client Configuration");break;

		/* RFC 3825 */
		case 123 :	str = _T("GeoConf");break;

		/* RFC 3925 */
		case 124 :	str = _T("Vendor-Identifying Vendor Class");break;
		case 125 :	str = _T("Vendor-Identifying Vendor-Specific Information");break;

		/* others (from IANA)*/

		case 128 :	str = _T("Etherboot signature. 6 bytes: E4:45:74:68:00:00 || DOCSIS \"full security\" server IP address || TFTP Server IP address - for IP Phone software load");break;
		case 129 :	str = _T("Kernel options. Variable length string || Call Server IP address");break;
		case 130 :	str = _T("Ethernet interface. Variable length string. || Discrimination string - to identify vendor");break;
		case 131 :	str = _T("Remote statistics server IP address");break;
		case 132 :	str = _T("802.1P VLAN ID");break;
		case 133 :	str = _T("802.1Q L2 Priority");break;
		case 134 :	str = _T("Diffserv Code Point");break;
		case 135 :	str = _T("HTTP Proxy for phone-specific applications");break;
		case 150 :	str = _T("Etherboot	|| GRUB configuration path name");break;
		case 177 :	str = _T("PacketCable and CableHome (replaced by 122)");break;

/*
   128     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   129     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   130     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   131     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   132     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   133     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   134     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   135     PXE - undefined (vendor specific)                     (Tentatively Assigned - 23 Jun 2005)
   150     TFTP server address                                   (Tentatively Assigned - 23 Jun 2005)
   175     Etherboot											 (Tentatively Assigned - 23 Jun 2005)
   176     IP Telephone											 (Tentatively Assigned - 23 Jun 2005)
   177     Etherboot											 (Tentatively Assigned - 23 Jun 2005)
   208     pxelinux.magic (string) = F1:00:74:7E (241.0.116.126) (Tentatively Assigned - 23 Jun 2005)
   209     pxelinux.configfile (text)                            (Tentatively Assigned - 23 Jun 2005)
   210     pxelinux.pathprefix (text)                            (Tentatively Assigned - 23 Jun 2005)
   211     pxelinux.reboottime (unsigned integer 32 bits)        (Tentatively Assigned - 23 Jun 2005)
   220     Subnet Allocation Option                              (Tentatively Assigned - 23 Jun 2005)
   221     Virtual Subnet Selection Option	                     (Tentatively Assigned - 23 Jun 2005)
 */
		default :
			if(optIdIn>=224 && optIdIn<=254)
				str = _T("- Private Use -");
			else
				str = _T("- unknown -");
			break;
	}

	return str;
}

//---------------------------------------------------------------------------
CString MDHCPInfoDesc::GetOptionValueIP4(MDHCPOption* optIn)
{
	CString str;
	in_addr ia;
	
	if(optIn==NULL){
		str.Empty();
		return str;
	}
	if(optIn->optionLen!=4){
		str.Format(_T("Invalid size: %u"), optIn->optionLen);
		return str;
	}

	ia.S_un.S_un_b.s_b1 = optIn->optionData[0];
	ia.S_un.S_un_b.s_b2 = optIn->optionData[1];
	ia.S_un.S_un_b.s_b3 = optIn->optionData[2];
	ia.S_un.S_un_b.s_b4 = optIn->optionData[3];

	str = inet_ntoa(ia);

	return str;
}

CString MDHCPInfoDesc::GetOptionValueIP4n(MDHCPOption* optIn)
{
	CString str;
	in_addr ia;
	BYTE i, cnt;
	
	str.Empty();
	if(optIn==NULL) return str;
	if((optIn->optionLen % 4)!=0){
		str.Format(_T("Invalid size: %u"), optIn->optionLen);
		return str;
	}

	cnt = optIn->optionLen / 4;
	for(i=0; i<cnt; i++){
		if(i!=0) str += _T(", ");

		ia.S_un.S_un_b.s_b1 = optIn->optionData[4*i];
		ia.S_un.S_un_b.s_b2 = optIn->optionData[4*i + 1];
		ia.S_un.S_un_b.s_b3 = optIn->optionData[4*i + 2];
		ia.S_un.S_un_b.s_b4 = optIn->optionData[4*i + 3];

		str += inet_ntoa(ia);
	}

	return str;
}

CString MDHCPInfoDesc::GetOptionValueStr(MDHCPOption* optIn)
{
	CString str;
	BYTE i, cnt;
	char ccc[2];
	
	str.Empty();
	if(optIn==NULL) return str;
	if(optIn->optionLen==0){
		str = _T("Invalid size: 0");
		return str;
	}

	cnt = optIn->optionLen;
	for(i=0; i<cnt; i++){
		ccc[0] = (char)optIn->optionData[i];
		ccc[1] = 0;

		str += ccc;
	}

	return str;
}

CString MDHCPInfoDesc::GetOptionValueSeconds(MDHCPOption* optIn)
{
	CString str, sss;
	in_addr ia;
	DWORD time;

	int tD, tM, tH, tS;
	
	if(optIn==NULL){
		str.Empty();
		return str;
	}
	if(optIn->optionLen!=4){
		str.Format(_T("Invalid size: %u"), optIn->optionLen);
		return str;
	}

	ia.S_un.S_un_b.s_b1 = optIn->optionData[3];
	ia.S_un.S_un_b.s_b2 = optIn->optionData[2];
	ia.S_un.S_un_b.s_b3 = optIn->optionData[1];
	ia.S_un.S_un_b.s_b4 = optIn->optionData[0];

	tD = 0;
	tH = 0;
	tM = 0;
	tS = 0;
	time = ia.S_un.S_addr;

	while(time>=86400){
		tD++;
		time -= 86400;
	}
	while(time>=3600){
		tH++;
		time -= 3600;
	}
	while(time>=60){
		tM++;
		time -= 60;
	}
	tS = time;

	if(tD>0){
		if(tD==1) sss = _T("1 day");
		else      sss.Format(_T("%d days"), tD);
		str = sss;
	}
	if(tH>0){
		if(tH==1) sss = _T("1 hour");
		else      sss.Format(_T("%d hours"), tH);
		if(!str.IsEmpty())
			str += _T(", ");
		str += sss;
	}
	if(tM>0){
		if(tM==1) sss = _T("1 minute");
		else      sss.Format(_T("%d minutes"), tM);
		if(!str.IsEmpty())
			str += _T(", ");
		str += sss;
	}
	if(tS>0){
		if(tS==1) sss = _T("1 second");
		else      sss.Format(_T("%d seconds"), tS);
		if(!str.IsEmpty())
			str += _T(", ");
		str += sss;
	}

	return str;
}

CString MDHCPInfoDesc::GetOptionValueDhcpMessageType(MDHCPOption* optIn)
{
	CString str;
	BYTE optMsgType;
	
	if(optIn==NULL){
		str.Empty();
		return str;
	}
	if(optIn->optionLen!=1){
		str.Format(_T("Invalid size: %u"), optIn->optionLen);
		return str;
	}

	optMsgType = optIn->optionData[0];

	switch(optMsgType){
		case 1 : str = _T("DHCPDISCOVER");break;
		case 2 : str = _T("DHCPOFFER");break;
		case 3 : str = _T("DHCPREQUEST");break;
		case 4 : str = _T("DHCPDECLINE");break;
		case 5 : str = _T("DHCPACK");break;
		case 6 : str = _T("DHCPNAK");break;
		case 7 : str = _T("DHCPRELEASE");break;
		case 8 : str = _T("DHCPINFORM");break;
		case 9 : str = _T("DHCPFORCERENEW");break;
		case 10 : str = _T("DHCPLEASEQUERY");break;
		case 11 : str = _T("DHCPLEASEUNASSIGNED");break;
		case 12 : str = _T("DHCPLEASEUNKNOWN");break;
		case 13 : str = _T("DHCPLEASEACTIVE");break;
		default :
			str = _T("");
			break;
	}

	return str;
}

CString MDHCPInfoDesc::GetOptionValueUnimplemented(MDHCPOption* optIn)
{
	CString str;
	char ccc[4];
	BYTE i;
	
	str.Empty();
	if(optIn==NULL) return str;

	for(i=0; i<optIn->optionLen; i++){
		BuildHexVal(ccc, optIn->optionData[i]);
		ccc[2] = ' ';
		ccc[3] = 0;
		str += ccc;
	}

	return str;
}

CString MDHCPInfoDesc::GetOptionValue(MDHCPOption* optIn)
{
	CString str;

	str.Empty();
	if(optIn==NULL) return str;
	
	switch(optIn->optionId){
		case 1 :
		case 16 :
		case 28 :
		case 32 :
		case 50 :
		case 54 :
			str = GetOptionValueIP4(optIn);
			break;

		case 3 :
		case 4 :
		case 5 :
		case 6 :
		case 7 :
		case 8 :
		case 9 :
		case 10 :
		case 11 :
		case 41 :
		case 42 :
		case 44 :
		case 45 :
		case 48 :
		case 49 :
		case 65 :
		case 68 :
		case 69 :
		case 70 :
		case 71 :
		case 72 :
		case 73 :
		case 74 :
		case 75 :
		case 76 :
			str = GetOptionValueIP4n(optIn);
			break;

		case 12 :
		case 14 :
		case 15 :
		case 17 :
		case 18 :
		case 40 :
		case 64 :
			str = GetOptionValueStr(optIn);
			break;

		case 35 :
		case 38 :
		case 51 :
		case 58 :
		case 59 :
			str = GetOptionValueSeconds(optIn);
			break;

		case 53 :
			str = GetOptionValueDhcpMessageType(optIn);
			break;

		default:
			str = GetOptionValueUnimplemented(optIn);
			break;
	}

	return str;
}

//---------------------------------------------------------------------------

CString MDHCPInfoDesc::DhcpMacToStr(BYTE* buff, BYTE buffSize)
{
	CString str;
	char ccc[49];
	BYTE i;

	str.Empty();
	if(buff==NULL) return str;
	if(buffSize==0) return str;

	memset(ccc, 0, 33);

	for(i=0; i<buffSize && i<16; i++){
		BuildHexVal(&ccc[3*i], buff[i]);

		ccc[3*i+2] = ':';
	}

	str = ccc;
	str = str.Left(str.GetLength() - 1);
	return str;
}

//---------------------------------------------------------------------------

CString MDHCPInfoDesc::FormatDhcpOptionAsString(MDHCPOption* optIn, bool extended)
{
	CString str;

	str.Empty();
	if(optIn==NULL) return str;

	if(extended)
		str.Format(_T("Option %u (%s): %s"), optIn->optionId, GetOptionName(optIn->optionId), GetOptionValue(optIn));
	else
		str.Format(_T("Option %u: %s"), optIn->optionId, GetOptionValue(optIn));

	return str;
}

//---------------------------------------------------------------------------

CString MDHCPInfoDesc::FormatDhcpOptionName(MDHCPOption* optIn)
{
	CString str;

	str = GetOptionName(optIn->optionId);

	return str;
}

CString MDHCPInfoDesc::FormatDhcpOptionValue(MDHCPOption* optIn)
{
	CString str;

	str = GetOptionValue(optIn);

	return str;
}

//---------------------------------------------------------------------------
